﻿using System;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Collections.ObjectModel;
using System.Web;
using System.Configuration;
using VioletDevelopmentLaboratory.Net.Data;
using VioletDevelopmentLaboratory.Net.Web.Configuration;

namespace VioletDevelopmentLaboratory.Net.Web.Component
{
	public class AttachmentFileManager
	{
		private String componentID;
		private String type;
		private String fileFolderPath;
		private PhysicalFileManager fileManager;

		private AttachmentFileManager() { }

		internal AttachmentFileManager(String componentID, String  componentType)
		{
			this.componentID = componentID;
			this.type = componentType;
			this.fileFolderPath = PhysicalFileManager.PathCombine(VUtility.WebApplicationPhysicalPath, VWebConfigurationReader.Path.FileFolder, type);
			this.fileManager = new PhysicalFileManager(fileFolderPath);
		}

		public static Boolean IsAllowExtension(String extensions, String fileName)
		{
			if (extensions == null)
				throw new ArgumentNullException("extensions");

			if (fileName == null)
				throw new ArgumentNullException("fileName");

			if (String.IsNullOrEmpty(extensions))
				throw new ArgumentOutOfRangeException("extensions");

			if (String.IsNullOrEmpty(fileName))
				throw new ArgumentOutOfRangeException("fileName");

			fileName = fileName.ToLower();

			extensions = extensions.ToLower();

			if (extensions == "*")
				return true;

			String[] _extensions = extensions.Split(new Char[] { ';' });
			for (Int32 i = 0; i < _extensions.Length; i++)
			{
				if (String.Compare(_extensions[i], fileName.Substring(fileName.LastIndexOf('.') + 1)) == 0)
				{
					return true;
				}
			}
			return false;
		}

		public AttachmentFileInfo Add(String relationID, HttpPostedFile postedFile, String description)
		{
			if (postedFile == null)
				throw new ArgumentNullException("postedFile");

			SqlParameter fileIDParameter = new SqlParameter();
			fileIDParameter.ParameterName = "@FileID";
			fileIDParameter.SqlDbType = SqlDbType.UniqueIdentifier;
			fileIDParameter.Direction = ParameterDirection.Output;

			//DB에 파일정보 저장
			SqlClientAgent.ExecuteNonQuery(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure, "VWeb_File_Create",
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", this.componentID),
				String.IsNullOrEmpty(relationID) ? new SqlParameter("@RelationID", DBNull.Value) : new SqlParameter("@RelationID", relationID),
				new SqlParameter("@OriginalFileName", Path.GetFileName(postedFile.FileName)),
				new SqlParameter("@ContentType", postedFile.ContentType),
				new SqlParameter("@Length", postedFile.ContentLength),
				new SqlParameter("@Description", description),
				fileIDParameter
			);

			String saveFilePath = "";
			String fileID = fileIDParameter.Value.ToString().ToLower();
			//물리적 파일 저장
			this.fileManager.Save(postedFile, fileID + Path.GetExtension(postedFile.FileName), out saveFilePath);

			return GetAttachmentFileInfo(fileID);
		}

		public void LinkRelationID(String[] fileIDs, String relationID)
		{
			if (relationID == null)
				throw new ArgumentNullException("relationID");

			if (String.IsNullOrEmpty(relationID))
				throw new ArgumentOutOfRangeException("relationID");

			if (!VUtility.IsGuid(relationID))
				throw new FormatException("relationID must Guid.");

			String linkFileQuery = "";
			foreach (String fileID in fileIDs)
			{
				if (!String.IsNullOrEmpty(fileID) && VUtility.IsGuid(fileID))
					linkFileQuery += String.Format("EXEC [VWeb_File_LinkRelationID] @ApplicationName, @ComponentID, '{0}', @RelationID;", fileID);
			}

			if (!String.IsNullOrEmpty(linkFileQuery))
			{
				SqlClientAgent.ExecuteNonQuery(
					ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
					CommandType.Text,
					String.Format("BEGIN TRANSACTION; {0} IF @@ERROR > 0 ROLLBACK; ELSE COMMIT;", linkFileQuery),
					new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
					new SqlParameter("@ComponentID", componentID),
					new SqlParameter("@RelationID", relationID)
				);
			}
		}

		public void UnlinkRelationID(String relationID)
		{
			if (relationID == null)
				throw new ArgumentNullException("relationID");

			if (String.IsNullOrEmpty(relationID))
				throw new ArgumentOutOfRangeException("relationID");

			if (!VUtility.IsGuid(relationID))
				throw new FormatException("relationID must Guid.");

			SqlClientAgent.ExecuteNonQuery(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure, "VWeb_File_UnlinkRelationID",
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", this.componentID),
				new SqlParameter("@RelationID", relationID)
			);
		}

		public void RemoveAll()
		{
			//실제 파일 제거
			DataSet dateset = SqlClientAgent.ExecuteDataSet(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure, "VWeb_File_GetAllFileIDs",
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", componentID)
			);

			Int32 rowsCount = dateset.Tables[0].Rows.Count;

			if (rowsCount > 0)
			{
				foreach (DataRow row in dateset.Tables[0].Rows)
				{
					this.fileManager.Delete(
						row["FileID"].ToString() + Path.GetExtension(row["OriginalFileName"].ToString())
					);
				}
				for (Int32 i = 0; i < rowsCount; i++)
				{
					
				}
			}

			//DB에서 파일 정보 제거
			SqlClientAgent.ExecuteNonQuery(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure, "VWeb_File_DeleteAll",
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", this.componentID)
			);
		}

		public void RemoveAll(String relationID)
		{
			if (relationID == null)
				throw new ArgumentNullException("relationID");

			if (String.IsNullOrEmpty(relationID))
				throw new ArgumentOutOfRangeException("relationID");

			if (!VUtility.IsGuid(relationID))
				throw new FormatException("relationID must Guid.");

			//물리적 파일 제거
			DataSet dateset = SqlClientAgent.ExecuteDataSet(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure, "VWeb_File_GetFileIDs",
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", componentID),
				new SqlParameter("@RelationID", relationID)
			);

			Int32 rowsCount = dateset.Tables[0].Rows.Count;

			if (rowsCount > 0)
			{
				foreach (DataRow row in dateset.Tables[0].Rows)
				{
					this.fileManager.Delete(
						row["FileID"].ToString() + Path.GetExtension(row["OriginalFileName"].ToString())
					);
				}
			}

			//DB에서 파일 정보 제거
			SqlClientAgent.ExecuteNonQuery(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure, "VWeb_File_DeleteAllByRelationID",
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", this.componentID),
				new SqlParameter("@RelationID", relationID)
			);
		}

		public AttachmentFileInfo GetAttachmentFileInfo(String fileID)
		{
			if (fileID == null)
				throw new ArgumentNullException("fileID");

			if (String.IsNullOrEmpty(fileID))
				throw new ArgumentOutOfRangeException("fileID");

			if (!VUtility.IsGuid(fileID))
				throw new FormatException("fileID must Guid.");

			SqlDataReader reader = SqlClientAgent.ExecuteReader(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure, "VWeb_File_GetFile",
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", this.componentID),
				new SqlParameter("@FileID", fileID)
			);

			AttachmentFileInfo fileInfo = null;

			try
			{
				if (reader.HasRows)
				{
					reader.Read();

					String componentID = reader["ComponentID"].ToString();

					fileInfo = new AttachmentFileInfo(
						reader["ApplicationName"].ToString(),
						componentID,
						this.type,
						reader["RelationID"].ToString(),
						fileID,
						reader["OriginalFileName"].ToString(),
						reader["ContentType"].ToString(),
						(Int32)reader["DownloadCount"],
						BoardUtil.GetAttachmentFileDownloadUrl(componentID, fileID),
						reader["Description"].ToString()
					);
				}
			}
			finally
			{
				reader.Close();
			}

			return fileInfo;
		}

		public AttachmentFileInfoCollection GetAttachmentFileInfoCollection(String relationID)
		{
			if (relationID == null)
				throw new ArgumentNullException("relationID");

			if (String.IsNullOrEmpty(relationID))
				throw new ArgumentOutOfRangeException("relationID");

			if (!VUtility.IsGuid(relationID))
				throw new FormatException("relationID must Guid.");

			SqlDataReader reader = SqlClientAgent.ExecuteReader(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure, "VWeb_File_GetFiles",
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", componentID),
				new SqlParameter("@RelationID", relationID)
			);

			AttachmentFileInfoCollection fileInfoCollection = null;

			try
			{
				if (reader.HasRows)
				{
					String fileID = "";
					fileInfoCollection = new AttachmentFileInfoCollection();

					AttachmentFileInfo fileInfo = null;
					while (reader.Read())
					{
						fileID = reader["FileID"].ToString();

						fileInfo = new AttachmentFileInfo(
							VWebConfigurationReader.ApplicationName,
							componentID,
							this.type,
							reader["RelationID"].ToString(),
							fileID,
							reader["OriginalFileName"].ToString(),
							reader["ContentType"].ToString(),
							(Int32)reader["DownloadCount"],
							BoardUtil.GetAttachmentFileDownloadUrl(componentID, fileID),
							reader["Description"].ToString());

						if (fileInfo.UploadFile.PhysicalFile.Exists)
							fileInfoCollection.Add(fileInfo);
					}
				}
			}
			finally
			{
				reader.Close();
			}

			return fileInfoCollection;
		}

		public static AttachmentFileInfoCollection GetTempAttachmentFileInfo(String componentID, String componentType)
		{
			if (componentID == null)
				throw new ArgumentNullException("componentID");

			if (componentType == null)
				throw new ArgumentNullException("componentType");

			if (String.IsNullOrEmpty(componentID))
				throw new ArgumentOutOfRangeException("componentID");

			if (String.IsNullOrEmpty(componentType))
				throw new ArgumentOutOfRangeException("componentType");

			SqlDataReader reader = SqlClientAgent.ExecuteReader(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure, "VWeb_File_GetTempFiles",
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", componentID)
				);

			AttachmentFileInfoCollection fileInfoCollection = null;

			try
			{
				if (reader.HasRows)
				{
					String fileID = "";
					fileInfoCollection = new AttachmentFileInfoCollection();
					while (reader.Read())
					{
						fileID = reader["FileID"].ToString();

						fileInfoCollection.Add(new AttachmentFileInfo(
							reader["ApplicationName"].ToString(),
							reader["ComponentID"].ToString(),
							componentType,
							reader["RelationID"].ToString(),
							fileID,
							reader["OriginalFileName"].ToString(),
							reader["ContentType"].ToString(),
							(Int32)reader["DownloadCount"],
							"",
							reader["Description"].ToString())
						);
					}
				}
			}
			finally
			{
				reader.Close();
			}

			return fileInfoCollection;
		}

		public static void Remove(String componentID, String fileID, String comopnentType)
		{
			if (componentID == null)
				throw new ArgumentNullException("componentID");

			if (fileID == null)
				throw new ArgumentNullException("fileID");

			if (comopnentType == null)
				throw new ArgumentNullException("comopnentType");

			if (String.IsNullOrEmpty(componentID))
				throw new ArgumentOutOfRangeException("componentID");

			if (String.IsNullOrEmpty(fileID))
				throw new ArgumentOutOfRangeException("fileID");

			if (String.IsNullOrEmpty(comopnentType))
				throw new ArgumentOutOfRangeException("comopnentType");

			if (!VUtility.IsGuid(fileID))
				throw new FormatException("fileID must Guid.");

			AttachmentFileManager manager = new AttachmentFileManager(componentID, comopnentType);

			manager.GetAttachmentFileInfo(fileID).Remove();
		}
	}

	[Serializable]
	public class AttachmentFileInfo
	{
		private String applicationName;
		public String ApplicationName { get { return this.applicationName; } }

		private String componentID;
		public String ComponentID { get { return this.componentID; } }

		private String relationID;
		public String RelationID { get { return this.relationID; } }

		private String fileID;
		public String FileID { get { return this.fileID; } }

		private Int32 downloadCount;
		public Int32 DownloadCount { get { return this.downloadCount; } }

		private String downloadUrl;
		public String DownloadUrl { get { return this.downloadUrl; } }

		private UploadFileInfo uploadFile;
		public UploadFileInfo UploadFile { get { return this.uploadFile; } }

		internal AttachmentFileInfo(String applicationName, String componentID, String componentType, String relationID, String fileID, String originalFileName, String contentType, Int32 downloadCount, String downloadUrl, String description)
		{
			this.applicationName = applicationName;
			this.componentID = componentID;
			this.relationID = relationID;
			this.fileID = fileID;
			this.downloadCount = downloadCount;
			this.downloadUrl = downloadUrl;

			String savedFileName = fileID + Path.GetExtension(originalFileName);

			this.uploadFile = new UploadFileInfo(fileID, originalFileName,
				PhysicalFileManager.PathCombine(VUtility.WebApplicationPhysicalPath, VWebConfigurationReader.Path.FileFolder, componentType, savedFileName),
				contentType,
				description);
		}

		public void Move(String destComponentID)
		{
			if (destComponentID == null)
				throw new ArgumentNullException("destComponentID");

			if (String.IsNullOrEmpty(destComponentID))
				throw new ArgumentOutOfRangeException("destComponentID");

			Object returnValue = null;

			SqlClientAgent.ExecuteNonQuery(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure, "VWeb_File_Move",
				out returnValue,
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", this.ComponentID),
				new SqlParameter("@FileID", this.FileID),
				new SqlParameter("@DestComponentID", destComponentID)
			);
		}

		public void Remove()
		{
			//물리적 파일 제거
			this.UploadFile.PhysicalFile.Delete();

			//DB에서 파일 정보 제거
			SqlClientAgent.ExecuteNonQuery(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure, "VWeb_File_Delete",
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", this.ComponentID),
				new SqlParameter("@FileID", this.FileID)
			);
		}

		public void AddDownloadCount(Int32 addCount)
		{
			SqlClientAgent.ExecuteNonQuery(
				ConfigurationManager.ConnectionStrings[VWebConfigurationReader.ConnectionStringName].ConnectionString,
				CommandType.StoredProcedure, "VWeb_File_UpdateDownloadCount",
				new SqlParameter("@ApplicationName", VWebConfigurationReader.ApplicationName),
				new SqlParameter("@ComponentID", this.ComponentID),
				new SqlParameter("@FileID", this.FileID),
				new SqlParameter("@AddDownloadCount", addCount)
			);
		}
	}

	[Serializable]
	public class AttachmentFileInfoCollection : Collection<AttachmentFileInfo> { }
}
